#include <array>
#include <vector>

#include <iostream>
#include <tiff/tiffio.h>

#include"demo.h"


void tiffInfo(TIFF *tif) {

    debugx("" );
    uint16_t config = PLANARCONFIG_CONTIG;
    TIFFGetField(tif, TIFFTAG_PLANARCONFIG, &config);
    qDebug()<<"\t config:"<<config;

    qDebug()<<"\t TIFFGetMode: " << TIFFGetMode(tif);
    qDebug()<<"\t TIFFIsTiled: " << TIFFIsTiled(tif);
    qDebug()<<"\t TIFFIsByteSwapped: " << TIFFIsByteSwapped(tif);
    qDebug()<<"\t TIFFIsUpSampled: " << TIFFIsUpSampled(tif);
    qDebug()<<"\t TIFFIsMSB2LSB: " << TIFFIsMSB2LSB(tif);
    qDebug()<<"\t TIFFIsBigEndian: " << TIFFIsBigEndian(tif);
    qDebug()<<"\t TIFFIsBigTIFF: " << TIFFIsBigTIFF(tif);
    qDebug()<<"\t TIFFFileno: " << TIFFFileno(tif);


    qDebug()<<"\t TIFFScanlineSize: " << TIFFScanlineSize(tif);
    qDebug()<<"\t TIFFRasterScanlineSize: " << TIFFRasterScanlineSize(tif);
    qDebug()<<"\t TIFFStripSize: " << TIFFStripSize(tif);
    qDebug()<<"\t TIFFTileRowSize: " << TIFFTileRowSize(tif);
    qDebug()<<"\t TIFFTileSize: " << TIFFTileSize(tif);

    uint32_t width, height;
    size_t npixels;
    uint32_t* raster;

    TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &width);
    TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &height);
    npixels = width * height;
    raster = (uint32_t*) _TIFFmalloc(npixels * sizeof (uint32_t));
    if (raster != NULL) {
        if (TIFFReadRGBAImage(tif, width, height, raster, 0)) {
            //  ...process raster data...
        }
        _TIFFfree(raster);
    }
    qDebug()<<"\t  width  : "<< width<<"\n\t  height  : "<< height;

    int dircount = 0;

    auto dir = TIFFReadDirectory(tif);
    while (dir) {
        dircount++;
    }
    qDebug()<<"\t  directories  : "<< dircount;

}

void tiffImage(TIFF *tif) {

    TIFFRGBAImage img;
    char emsg[1024];

    if (!TIFFRGBAImageBegin(&img, tif, 0, emsg)) {
        TIFFError("",  "%s", emsg);
        return ;
    }

    size_t npixels;
    uint32_t* raster;

    npixels = img.width * img.height;
    raster = (uint32_t*) _TIFFmalloc(npixels * sizeof (uint32_t));
    if (raster != NULL) {
        if (TIFFRGBAImageGet(&img, raster, img.width, img.height)) {
            //  ...process raster data...
        }
        _TIFFfree(raster);
    }
    TIFFRGBAImageEnd(&img);

    debugx("\n\t  width  :%d  height  :%d  ",img.width,img.height);
}

void tiffScanline(TIFF *tif) {
    uint32_t imagelength;
    tdata_t buf;
    uint32_t row;

    TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &imagelength);
    buf = _TIFFmalloc(TIFFScanlineSize(tif));
    for (row = 0; row < imagelength; row++)
        TIFFReadScanline(tif, buf, row, 0);
    _TIFFfree(buf);
}
void tiffScanline1(TIFF *tif) {
    uint32_t imagelength;
    tdata_t buf;
    uint32_t row;
    uint32_t config;

    TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &imagelength);
    TIFFGetField(tif, TIFFTAG_PLANARCONFIG, &config);
    buf = _TIFFmalloc(TIFFScanlineSize(tif));
    if (config == PLANARCONFIG_CONTIG) {
        for (row = 0; row < imagelength; row++)
            TIFFReadScanline(tif, buf, row, 0);
    } else if (config == PLANARCONFIG_SEPARATE) {
        uint16_t s, nsamples;

        TIFFGetField(tif, TIFFTAG_SAMPLESPERPIXEL, &nsamples);
        for (s = 0; s < nsamples; s++)
            for (row = 0; row < imagelength; row++)
                TIFFReadScanline(tif, buf, row, s);
    }
    _TIFFfree(buf);
}
void tiffTile(TIFF *tif) {
    uint32_t imageWidth, imageLength;
    uint32_t tileWidth, tileLength;
    uint32_t x, y;
    tdata_t buf;

    TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &imageWidth);
    TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &imageLength);
    TIFFGetField(tif, TIFFTAG_TILEWIDTH, &tileWidth);
    TIFFGetField(tif, TIFFTAG_TILELENGTH, &tileLength);
    buf = _TIFFmalloc(TIFFTileSize(tif));
    for (y = 0; y < imageLength; y += tileLength)
        for (x = 0; x < imageWidth; x += tileWidth)
            TIFFReadTile(tif, buf, x, y, 0,0);
    _TIFFfree(buf);
}

void tiffStrips (TIFF *tif) {
    tdata_t buf;
    tstrip_t strip;
    uint32_t* bc;
    uint32_t stripsize;

    TIFFGetField(tif, TIFFTAG_STRIPBYTECOUNTS, &bc);
    stripsize = bc[0];
    buf = _TIFFmalloc(stripsize);
    for (strip = 0; strip < TIFFNumberOfStrips(tif); strip++) {
        if (bc[strip] > stripsize) {
            buf = _TIFFrealloc(buf, bc[strip]);
            stripsize = bc[strip];
        }
        TIFFReadRawStrip(tif, strip, buf, bc[strip]);
    }
    _TIFFfree(buf);
}

void tiffEncodeTile (TIFF *tif) {
    tdata_t buf;
    ttile_t tile;

    buf = _TIFFmalloc(TIFFTileSize(tif));
    for (tile = 0; tile < TIFFNumberOfTiles(tif); tile++)
        TIFFReadEncodedTile(tif, tile, buf, (tsize_t) -1);
    _TIFFfree(buf);
}

void tiffMain() {

    auto filePath = "D:/image/tifTest/palette-1c-1b.tiff";
    // filePath = "D:/image/BigTIFFSamples/BigTIFFMotorola.tif";
    //  filePath = "D:/image/BigTIFFSamples/BigTIFFMotorolaLongStrips.tif";
    //  filePath = "D:/image/tifTest/test_float64_predictor2_be_lzw.tiff";
    filePath = "D:/image/tifTest/test_ifd_loop_subifd.tiff";


    TIFF *tif = TIFFOpen(filePath, "r");
    if (!tif) {
        debugx("open fail:%s ",filePath);
        return ;
    }
    debugx("\n\tfilePath: %s ",filePath);
    tiffInfo(tif);


    tiffImage(tif);
    // tiffScanline(tif);
    // tiffScanline1(tif);

    TIFFClose(tif);
    std::cout << "\n\n ";

    std::cout << "\n\n ";

}

